﻿//using CLVisionCommu;
using CLVisionCommu;
using NeuroCheck.BaseTypes.DataFormatConverter;

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Channels;
using System.Text;
using System.Threading.Tasks;

namespace CLVisionCommuDFC
{
    public partial class FmtCnvCore : INcFmtCnvDriver, IDisposable
    {
        private static volatile FmtCnvCore m_Instance = null;
        private List<int> m_alAssignedChannelIDs;

        ChannelOptionManager channelOptionManager = null;

        private NcFmtCnvErrorObject m_NcFmtCnvErrorObject = new NcFmtCnvErrorObject();
        private NcFmtCnvReturnCode m_ReturnCode;
        private string m_LastErrorMessage;

        public static FmtCnvCore CreateInstance()
        {
            lock (typeof(FmtCnvCore))
            {
                if (null == m_Instance)
                {
                    try
                    {
                        m_Instance = new FmtCnvCore();
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                }
            }
            return m_Instance;
        }

        public bool ControlChannel(int channelID, NcFmtCnvControlChannelCodeInfo selCode, ref object data, ref object dataEx)
        {
            switch (selCode)
            {
                case NcFmtCnvControlChannelCodeInfo.CheckValid:
                    if (channelOptionManager == null)
                    {
                        m_ReturnCode = NcFmtCnvReturnCode.NoOptionsForChannelID;
                        m_LastErrorMessage = "Pin无效！请删除数据格式转换器，并重新加载！";
                        return false;
                    }
                    break;
                case NcFmtCnvControlChannelCodeInfo.GetInputOutputCaps:
                    //首次启动时创建
                    data = NcFmtCnvIOCapsInfo.Both;
                    m_alAssignedChannelIDs = new List<int>();
                    if (channelOptionManager == null)
                    {
                        channelOptionManager = new ChannelOptionManager(channelID, out int ErrorCode, out string ErrorText);
                        if (ErrorCode == -1)
                        {
                            channelOptionManager = null;
                            m_ReturnCode = NcFmtCnvReturnCode.NoChannelAvailable;
                            m_LastErrorMessage = ErrorText;
                            return false;
                        }
                        m_alAssignedChannelIDs.Add(channelID);
                    }
                    m_ReturnCode = NcFmtCnvReturnCode.NoError;
                    m_LastErrorMessage = "NoError";
                    break;
                case NcFmtCnvControlChannelCodeInfo.SetDeviceManagerInterface:
                case NcFmtCnvControlChannelCodeInfo.Notification:
                case NcFmtCnvControlChannelCodeInfo.GetDevice:
                case NcFmtCnvControlChannelCodeInfo.SetDevice:
                case NcFmtCnvControlChannelCodeInfo.GetFileName:
                case NcFmtCnvControlChannelCodeInfo.Flush:
                case NcFmtCnvControlChannelCodeInfo.Refresh:
                case NcFmtCnvControlChannelCodeInfo.ShowSettingsDialog:
                default:
                    break;
            }
            return true;
        }

        public bool ControlDriver(NcFmtCnvControlDriverCodeInfo selCode, ref object data, ref object dataEx)
        {
            switch (selCode)
            {
                case NcFmtCnvControlDriverCodeInfo.GetXmlSettingsString:
                case NcFmtCnvControlDriverCodeInfo.SetXmlSettingsString:
                default:
                    break;
            }
            return true;
        }

        public bool ControlPin(int channelID, int pinIDOrIndex, NcFmtCnvControlPinCodeInfo selCode, ref object data, ref object dataEx)
        {
            switch (selCode)
            {
                case NcFmtCnvControlPinCodeInfo.WriteToPin:
                    try
                    {
                        if (channelOptionManager == null)
                        {
                            m_ReturnCode = NcFmtCnvReturnCode.NoOptionsForChannelID;
                            m_LastErrorMessage = "Pin无效！";
                            return false;
                        }
                        var pinWrite = channelOptionManager.pinInfoDataList.Where(x => x.ID == pinIDOrIndex).FirstOrDefault();

                        var tagWrite = (ValueTuple<string, int>)pinWrite.Tag;
                        if (tagWrite.Item1.ToString() == "Constant")
                        {
                            string constantName = pinWrite.Name;
                            //判断是否为一个点位多个bool数据
                            if (pinWrite.Isbit)
                            {
                                bool[] boolArray = new bool[16];
                                for (int i = 0; i < boolArray.Length; i++)
                                {
                                    boolArray[i] = (i == pinWrite.BitIndex) && Convert.ToBoolean(data);
                                }
                                ushort ushortValue = 0;
                                for (int i = 0; i < 16; i++)
                                {
                                    ushortValue |= (ushort)(boolArray[i] ? (1 << i) : 0);
                                }
                                data = Convert.ToDouble(ushortValue);
                            }

                            channelOptionManager.commuOptionManager.CommuOption.SendConstantData(constantName, Convert.ToDouble(data), out int ErrorCode, out string ErrorText);
                            if (ErrorCode == -1)
                            {
                                m_ReturnCode = NcFmtCnvReturnCode.WriteToPinError;
                                m_LastErrorMessage = ErrorText;
                                return false;
                            }
                        }
                        else if (tagWrite.Item1.ToString() == "Object")
                        {
                            // [10.1.1]INT(test)";
                            int objectID = int.Parse(pinWrite.Name.Split('[')[1].Split('.')[0]);
                            int itemIndex = int.Parse(pinWrite.Name.Split('[')[1].Split('.')[1]);
                            int arrayIndex = int.Parse(pinWrite.Name.Split('[')[1].Split('.')[2].Split(']')[0]);
                            int arraySize = tagWrite.Item2;
                            int itemType = -1;
                            switch (pinWrite.DataType)
                            {
                                case NcFmtCnvPinDataTypeInfo.String:
                                    itemType = 4;
                                    break;
                                case NcFmtCnvPinDataTypeInfo.Int:
                                    itemType = 1;
                                    break;
                                case NcFmtCnvPinDataTypeInfo.Double:
                                    itemType = 3;
                                    break;
                                case NcFmtCnvPinDataTypeInfo.Bool:
                                    itemType = 5;
                                    break;
                                default:
                                    itemType = -1;
                                    break;
                            }
                            channelOptionManager.commuOptionManager.CommuOption.avcSetItemArrayData(objectID, itemIndex, itemType, arrayIndex, data, out int ErrorCode, out string ErrorText);
                            if (ErrorCode == -1)
                            {
                                m_ReturnCode = NcFmtCnvReturnCode.WriteToPinError;
                                m_LastErrorMessage = ErrorText;
                                return false;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        m_ReturnCode = NcFmtCnvReturnCode.WriteToPinError;
                        m_LastErrorMessage = ex.Message;
                    }
                    break;
                case NcFmtCnvControlPinCodeInfo.ReadFromPin:
                    try
                    {
                        if (channelOptionManager == null)
                        {
                            m_ReturnCode = NcFmtCnvReturnCode.NoOptionsForChannelID;
                            m_LastErrorMessage = "Pin无效！";
                            return false;
                        }
                        var pinRead = channelOptionManager.pinInfoDataList.Where(x => x.ID == pinIDOrIndex).FirstOrDefault();

                        var tagRead = (ValueTuple<string, int>)pinRead.Tag;
                        if (tagRead.Item1 == "Constant")
                        {
                            string constantName = pinRead.Name;
                            channelOptionManager.commuOptionManager.CommuOption.ReceiveConstantData(constantName, out double RetValue, out int ErrorCode, out string ErrorText);

                            ////判断是否为一个点位存储多个bool数据
                            //if (pinRead.Isbit)
                            //{
                            //    //值转成bool数组
                            //    ushort value = Convert.ToUInt16(RetValue);
                            //    bool[] result = new bool[16];
                            //    for (int i = 0; i < 16; i++)
                            //    {
                            //        result[i] = (value & (1 << i)) != 0;
                            //    }
                            //    //提取数组中对应16位的值
                            //    RetValue = Convert.ToDouble(result[pinRead.BitIndex]);
                            //}

                            if (ErrorCode == -1)
                            {
                                m_ReturnCode = NcFmtCnvReturnCode.ReadFromPinError;
                                m_LastErrorMessage = ErrorText;
                                return false;
                            }
                            switch (pinRead.DataType)
                            {
                                case NcFmtCnvPinDataTypeInfo.Int:
                                    data = Convert.ToInt32(RetValue);
                                    break;
                                case NcFmtCnvPinDataTypeInfo.Bool:
                                    data = Convert.ToBoolean(RetValue);
                                    break;
                                default:
                                    break;
                            }

                        }
                        else if (tagRead.Item1 == "Object")
                        {
                            // [10.1.1]INT(test)";
                            int objectID = int.Parse(pinRead.Name.Split('[')[1].Split('.')[0]);
                            int itemIndex = int.Parse(pinRead.Name.Split('[')[1].Split('.')[1]);
                            int arrayIndex = int.Parse(pinRead.Name.Split('[')[1].Split('.')[2].Split(']')[0]);
                            int arraySize = tagRead.Item2;
                            int itemType = -1;
                            switch (pinRead.DataType)
                            {
                                case NcFmtCnvPinDataTypeInfo.String:
                                    itemType = 4;
                                    break;
                                case NcFmtCnvPinDataTypeInfo.Int:
                                    itemType = 1;
                                    break;
                                case NcFmtCnvPinDataTypeInfo.Double:
                                    itemType = 3;
                                    break;
                                case NcFmtCnvPinDataTypeInfo.Bool:
                                    itemType = 5;
                                    break;
                                default:
                                    itemType = -1;
                                    break;
                            }

                            channelOptionManager.commuOptionManager.CommuOption.avcGetItemArrayData(objectID, itemIndex, itemType, arrayIndex, out object RetValue, out int ErrorCode, out string ErrorText);
                            if (ErrorCode == -1)
                            {
                                m_ReturnCode = NcFmtCnvReturnCode.ReadFromPinError;
                                m_LastErrorMessage = ErrorText;
                                return false;
                            }
                            m_ReturnCode = NcFmtCnvReturnCode.NoError;
                            m_LastErrorMessage = string.Empty;
                            data = RetValue;
                        }
                    }
                    catch (Exception ex)
                    {
                        m_ReturnCode = NcFmtCnvReturnCode.ReadFromPinError;
                        m_LastErrorMessage = ex.Message;
                    }


                    break;
                case NcFmtCnvControlPinCodeInfo.GetPinInfoByPinIndex:
                    if (channelOptionManager == null)
                    {
                        m_ReturnCode = NcFmtCnvReturnCode.NoOptionsForChannelID;
                        m_LastErrorMessage = "Pin无效！";
                        return false;
                    }
                    var temp = channelOptionManager.pinInfoDataList.Where(x => x.ID == pinIDOrIndex).FirstOrDefault();
                    PinInfoData pinInfoData = (PinInfoData)data;

                    pinInfoData.ID = temp.ID;
                    pinInfoData.Name = temp.Name;
                    pinInfoData.PinType = temp.PinType;
                    pinInfoData.UserDefinedName = temp.UserDefinedName;
                    pinInfoData.DataType = temp.DataType;

                    data = pinInfoData;


                    break;
                case NcFmtCnvControlPinCodeInfo.GetPinInfoByPinId:
                    if (channelOptionManager == null)
                    {
                        m_ReturnCode = NcFmtCnvReturnCode.NoOptionsForChannelID;
                        m_LastErrorMessage = "Pin无效！";
                        return false;
                    }
                    var temp1 = channelOptionManager.pinInfoDataList.Where(x => x.ID == pinIDOrIndex).FirstOrDefault();
                    PinInfoData pinInfoData1 = (PinInfoData)data;

                    pinInfoData1.ID = temp1.ID;
                    pinInfoData1.Name = temp1.Name;
                    pinInfoData1.PinType = temp1.PinType;
                    pinInfoData1.UserDefinedName = temp1.UserDefinedName;
                    pinInfoData1.DataType = temp1.DataType;

                    data = pinInfoData1;
                    break;
                default:
                    break;
            }
            return true;
        }

        public bool CreateChannel(NcFmtCnvIOCapsInfo caps, ref object deviceDescription, out int channelID)
        {
            channelID = -1;
            switch (caps)
            {
                case NcFmtCnvIOCapsInfo.Input:
                case NcFmtCnvIOCapsInfo.Output:
                case NcFmtCnvIOCapsInfo.Both:
                    //新建通道时创建
                    if (channelOptionManager == null)
                    {
                        m_alAssignedChannelIDs = new List<int>();
                        channelID = GetNextAvailableChannelID();
                        channelOptionManager = new ChannelOptionManager(channelID, out int ErrorCode, out string ErrorText);
                        if (ErrorCode == -1)
                        {
                            channelOptionManager = null;
                            m_ReturnCode = NcFmtCnvReturnCode.NoChannelAvailable;
                            m_LastErrorMessage = ErrorText;
                            return false;
                        }
                        m_alAssignedChannelIDs.Add(channelID);


                        return true;
                    }
                    else
                    {
                        channelID = channelOptionManager.ChannelID;
                    }
                    break;
                default:
                    break;
            }
            return true;
        }

        public bool DeleteChannel(int channelID)
        {
            if (channelOptionManager == null)
            {
                m_ReturnCode = NcFmtCnvReturnCode.NoOptionsForChannelID;
                m_LastErrorMessage = "NoOptionsForChannelID";
                channelOptionManager = null;
                return false;
            }
            channelOptionManager.commuOptionManager.CommuOption.Dispose(out int ErrorCode, out string ErrorText);
            if (ErrorCode == -1)
            {
                m_ReturnCode = NcFmtCnvReturnCode.NoOptionsForChannelID;
                m_LastErrorMessage = ErrorText;
                return false;
            }
            m_alAssignedChannelIDs.Remove(channelID);
            channelOptionManager = null;

            return true;
        }

        public void Dispose()
        {

        }

        public bool GetChannelCount(out int channelCount)
        {
            channelCount = m_alAssignedChannelIDs.Count;
            return true;
        }

        public bool GetChannelDisplayName(int channelID, out string channelDisplayName)
        {
            if (channelOptionManager == null && m_alAssignedChannelIDs == null)
            {
                m_ReturnCode = NcFmtCnvReturnCode.NoOptionsForChannelID;
                m_LastErrorMessage = "NoOptionsForChannelID";
                channelDisplayName = "Modbus";
                return true;
            }
            if (channelOptionManager == null && m_alAssignedChannelIDs != null)
            {
                m_ReturnCode = NcFmtCnvReturnCode.NoOptionsForChannelID;
                m_LastErrorMessage = "NoOptionsForChannelID";
                channelDisplayName = "无效";
                return false;
            }

            channelDisplayName = "Modbus";
            m_ReturnCode = NcFmtCnvReturnCode.NoError;
            m_LastErrorMessage = string.Empty;
            return true;
        }

        public bool GetChannelID(int channelIndex, out int channelID)
        {
            channelID = 0;
            return true;
        }

        public bool GetFmtCnvInfo(out string name, out string description)
        {
            name = "CLVisionCommu";
            description = "NeuroCheck Communication "; //Properties.Resources.strFormatConverterDesc;
            return true;
        }

        public bool GetFmtCnvType(out NcFmtCnvTypeInfo type)
        {
            type = NcFmtCnvTypeInfo.OtherFormatter;
            return true;
        }

        public NcFmtCnvErrorObject GetLastError()
        {

            m_NcFmtCnvErrorObject.ErrorCode = m_ReturnCode;
            m_NcFmtCnvErrorObject.ErrorMessage = m_LastErrorMessage;
            return m_NcFmtCnvErrorObject;
        }

        public bool GetPinCount(int channelID, out int pinCount)
        {
            pinCount = channelOptionManager.pinInfoDataList.Count;
            return true;
        }

        private int GetNextAvailableChannelID()
        {
            m_alAssignedChannelIDs.Sort();
            for (int i = 0; i < m_alAssignedChannelIDs.Count; i++)
            {
                // Wenn die aktuelle ID nicht dem aktuellen Schleifen-Index entspricht
                // dann ist diese ID noch frei
                if (i != (int)m_alAssignedChannelIDs[i])
                {
                    return i;

                }
            }
            return m_alAssignedChannelIDs.Count;
        }

    }
}
